package com.lkf.rpc.stub;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.codec.serialization.ObjectEncoder;

public class RPCServer {

    //服务端占用端口
    private int port;
    //服务端准备处理客户端代理请求的接口包名称
    private String path;

    public RPCServer(int port, String path) {
        this.port = port;
        this.path = path;
    }

    /**
     * 客户端使用netty启动服务
     */
    public void start() {
        // boss线程组，用于处理连接
        EventLoopGroup bossgroup = new NioEventLoopGroup();
        // worker线程组，用于处理数据IO
        EventLoopGroup workergroup = new NioEventLoopGroup();
        try {
            // netty服务端启动类，配置netty参数
            ServerBootstrap bootstrap = new ServerBootstrap();
            // 配置线程组，服务端需要2个线程组
            bootstrap.group(bossgroup, workergroup)
                    // 配置channel类型，使用异步的服务器端 TCP Socket 连接
                    .channel(NioServerSocketChannel.class)
                    // 配置存放请求的队列的长度
                    .option(ChannelOption.SO_BACKLOG, 128)
                    // 配置启用心跳机制来检测长连接的存活性，即客户端的存活性
                    .childOption(ChannelOption.SO_KEEPALIVE, true)
                    // 本地端口
                    .localAddress(port)
                    // 配置netty的的channel，使用内部类ChannelInitializer创建
                    .childHandler(new ChannelInitializer<SocketChannel>() {

                        /**
                         * 初始化channel
                         * @param socketChannel
                         * @throws Exception
                         */
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            // 拿到channel的pipeline，用于添加自定义配置
                            ChannelPipeline pipeline = socketChannel.pipeline();
                            //添加编码器
                            pipeline.addLast("encoder", new ObjectEncoder())
                                    //添加解码器  构造方法第一个参数设置二进制数据的最大字节数  第二个参数设置具体使用哪个类解析器
                                    .addLast("decoder", new ObjectDecoder(Integer.MAX_VALUE, ClassResolvers.cacheDisabled(null)))
                                    //添加服务端业务处理类
                                    .addLast(new InvokeHandler(path));
                        }
                    });
            // 给netty绑定调用端口并等待建立socket链接
            ChannelFuture future = bootstrap.bind(port).sync();
            System.out.println("RPC服务端已启动");
            // 阻塞线程，防止程序运维完后关闭，直至socket连接关闭后才会关闭
            future.channel().closeFuture().sync();
        } catch (Exception e) {
            e.printStackTrace();
            bossgroup.shutdownGracefully();
            workergroup.shutdownGracefully();
        }
    }
}
